package com.qing.demo.netty.server;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.qing.demo.netty.domain.MsgAgreement;
import com.qing.demo.netty.domain.UserChannelInfo;
import com.qing.demo.netty.service.ExtServerService;
import com.qing.demo.netty.util.CacheUtil;
import com.qing.demo.netty.util.MsgUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;


/**
 * @author caozhipeng
 * @date 2025/7/25
 */
@Slf4j
public class MyServerHandler extends ChannelInboundHandlerAdapter {


    private ExtServerService extServerService;

    public MyServerHandler(ExtServerService extServerService) {
        this.extServerService = extServerService;
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        super.userEventTriggered(ctx, evt);
        if(evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent) evt;
            if(event.state()== IdleState.READER_IDLE){
                System.out.println("读空闲");
                ctx.writeAndFlush("读空闲:...客户端你在吗{我结尾是一个换行符用于处理半包粘包}...\r\n");
                ctx.close();
            }else if(event.state()== IdleState.WRITER_IDLE){
                System.out.println("写空闲");
                ctx.writeAndFlush("写空闲:...客户端你在吗{我结尾是一个换行符用于处理半包粘包}...\r\n");

            }else if(event.state()== IdleState.ALL_IDLE){
                System.out.println("读写空闲");
                ctx.writeAndFlush("读写空闲:...客户端你在吗{我结尾是一个换行符用于处理半包粘包}...\r\n");
            }
        }
        ctx.flush();
    }

    //   当客户端主动链接后，这个通道就是活跃的，可以发送数据给客户端
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        SocketChannel socketChannel=(SocketChannel)ctx.channel();
        System.out.println("链接报告开始");
        System.out.println("链接报告信息：有一个客户端链接到本地服务器");
        System.out.println("链接报告IP:"+ socketChannel.localAddress().getHostString());
        System.out.println("链接报告端口:"+ socketChannel.localAddress().getPort());
        System.out.println("链接报告结束");


//        保存用户信息
        UserChannelInfo userChannelInfo=new UserChannelInfo(socketChannel.localAddress().getHostString(),socketChannel.localAddress().getPort(),socketChannel.id().toString(),new Date());
        extServerService.getRedisUtil().pushObj(userChannelInfo);
        CacheUtil.cacheChannel.put(socketChannel.id().toString(),socketChannel);
//        通知客户端链接建立成功
        String string = "链接建立成功"+ DateUtil.date()+" "+socketChannel.localAddress().getHostString()+" \r\n";
        ctx.writeAndFlush(MsgUtil.buildMsg(socketChannel.id().toString(),string));
    }

    /**
     * 当客户端主动断开服务器连接后，这个通道就是不活跃的，不可以传递数据
     * @param ctx
     * @throws Exception
     */
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端断开链接: "+ctx.channel().localAddress().toString());
        extServerService.getRedisUtil().remove(ctx.channel().id().toString());
        CacheUtil.cacheChannel.remove(ctx.channel().id().toString(),ctx.channel());
    }

    // 异常处理
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        extServerService.getRedisUtil().remove(ctx.channel().id().toString());
        CacheUtil.cacheChannel.remove(ctx.channel().id().toString(),ctx.channel());
        System.out.println("异常信息："+cause.getMessage());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(DateUtil.now()+" 接收到消息内容："+msg);

        MsgAgreement msgAgreement=MsgUtil.json2Obj(msg.toString());

        String toChannelId=msgAgreement.getToChannelId();
//        判断接收消息用户是否在本服务器
        Channel channel=CacheUtil.cacheChannel.get(toChannelId);
        if(null!=channel){
            channel.writeAndFlush(MsgUtil.obj2Json(msgAgreement));
            return;
        }
//        如果未NULL则接收消息的用户不在本服务器，需要Push消息给全局
        log.info("接收消息的用户不在本服务器，需要Push消息给全局");
        extServerService.push(msgAgreement);
    }

}
